﻿Imports System.IO
Imports System.Threading
Imports System.Xml.Serialization
Imports System.Text.RegularExpressions
Imports System.Security.Cryptography
Imports Microsoft.Win32

Public Class Tools

    Private Declare Function SetThreadExecutionState Lib _
    "kernel32" (ByVal esflags As EXECUTION_STATE) As EXECUTION_STATE

#Region "Read/Write Settings"

    ''' <summary>
    ''' Diese Funktion serialisiert ein Objekt und speichert es als XML-Format Datei
    ''' </summary>
    ''' <param name="Obj">Das zu serialisierende Objekt</param>
    ''' <param name="FileName">Die XML Datei in der das Ergebnis gespeichert werden soll</param>
    Public Sub XMLSerialize(ByVal Obj As Object, ByVal FileName As String)
        Dim XML As New XmlSerializer(Obj.GetType)
        Dim FS As New FileStream(FileName, FileMode.Create)
        XML.Serialize(FS, Obj)
        FS.Close()
    End Sub

    ''' <summary>
    ''' Diese Funktion deserialisiert eine XML Datei und gibt das Ergebnis in ein Objekt zurück
    ''' </summary>
    ''' <param name="FileName">Die XML Datei aus der gelesen werden soll</param>
    Public Function XMLDeSerialize(ByVal Obj As Object, ByVal FileName As String) As Object
        Dim XML As New XmlSerializer(Obj.GetType)
        Dim FS As New StreamReader(FileName)
        Dim RetObj As Object = XML.Deserialize(FS)
        FS.Close()
        FS.Dispose()
        Return RetObj

    End Function


#End Region

#Region "MD5-Hash Funktionen"

    ''' <summary>
    ''' Prüft ob es sich um einen validen MD5-Hash handelt
    ''' </summary>
    Public Function isValidMD5(s As String) As Boolean

        Dim _regex As New Regex("[0-9a-f]{32}")

        If String.IsNullOrEmpty(s) Then
            Return False
        End If

        Dim _match As Match = _regex.Match(s)

        If _match.Success Then
            Return True
        Else
            Return False
        End If

    End Function

    ''' <summary>
    ''' Errechnet den MD5-Hash einer Datei
    ''' </summary>
    ''' <param name="sFile"></param>
    ''' <return></return>
    ''' <remarks></remarks>

    Public Function MD5FileHash(ByVal sFile As String) As String
        Dim MD5 As New MD5CryptoServiceProvider
        Dim Hash As Byte()
        Dim Result As String = ""
        Dim Tmp As String = ""

        Dim FN As New FileStream(sFile, FileMode.Open, FileAccess.Read, FileShare.Read, 8192)
        MD5.ComputeHash(FN)
        FN.Close()

        Hash = MD5.Hash
        For i As Integer = 0 To Hash.Length - 1
            Tmp = Hex(Hash(i))
            If Len(Tmp) = 1 Then Tmp = "0" & Tmp
            Result += Tmp
        Next
        Return Result
    End Function

#End Region

    ''' <summary>
    ''' Gibt zurück ob die angebene Datei ein Zip,Rar Archiv ist.
    ''' </summary>
    Public Function isFileArchive(ByVal _file As String) As Boolean

        If _file.Contains(".part") Then

            If _file.EndsWith(".part01.rar") Or _file.EndsWith(".part1.rar") Then
                Return True
            Else
                Return False
            End If

        End If

        If _file.EndsWith(".rar") Then
            Return True
        End If

        If _file.EndsWith(".zip") Then
            Return True
        End If

        If _file.EndsWith(".7z") Then
            Return True
        End If

    End Function

    ''' <summary>
    ''' Gibt zurück ob es sich um ein 64-bit OS handelt
    ''' </summary>
    Public Function isx64() As Boolean

        If IntPtr.Size = 8 Then
            Return True
        Else
            Return False
        End If

    End Function

    Public Function mSecToHMS(ByVal millSec As Double) As String
        '
        Dim ts As TimeSpan
        Dim totHrs As Integer
        Dim H, M, S, HMS As String
        '
        'Place milliseconds into timespand variable
        'to expose conversion properties
        ts = TimeSpan.FromMilliseconds(millSec)
        '
        'Get H M S values and format for leading zero
        'Add a trailing semi colon on Hours and minutes
        'Total hours will allow display of more than 24 hrs
        'while minutes and seconds will be limited to 0-59
        '
        totHrs = Math.Truncate(ts.TotalHours) 'strip away decimal points
        H = Format(totHrs, "0#") & ":"
        M = Format(ts.Minutes, "0#") & ":"
        S = Format(ts.Seconds, "0#")
        '
        'Combine Hours Minutes and seconds into HH:MM:SS string
        HMS = H & M & S
        '
        Return HMS

    End Function

    ''' <summary>
    ''' Gibt zurück ob es sich um ein Linux basiertes OS handelt.
    ''' </summary>
    Public Function isLinux() As Boolean

        Dim p As Integer = CInt(Environment.OSVersion.Platform)
        Return (p = 4) OrElse (p = 6) OrElse (p = 128)

    End Function

    ''' <summary>
    ''' Öffnet den Windows Explorer mit dem angebenen Pfad
    ''' </summary>
    Public Sub OpenExplorer(ByVal path As String)
        Dim p As New ProcessStartInfo
        p.Arguments = "/e,/select," & path & ""
        p.FileName = "explorer.exe"
        Process.Start(p)
    End Sub

    ''' <summary>
    ''' Errechnet den maximalen Download Speed den ein Thread haben darf.
    ''' </summary>
    Public Function CalculateMaxDownloadSpeed(ByVal _sfdl_max_thread As Integer, ByVal _active_thread_count As Integer, ByVal _max_speed As String) As Integer

        Dim _rt As Integer = 0

        Try

            If Integer.Parse(_max_speed) > 0 Or String.IsNullOrEmpty(_max_speed) = False Then

                If _sfdl_max_thread < _active_thread_count Then
                    _rt = CInt(Integer.Parse(_max_speed) / _sfdl_max_thread)
                Else
                    _rt = CInt(Integer.Parse(_max_speed) / _active_thread_count)
                End If
            Else
                _rt = 0
            End If


        Catch ex As Exception

        End Try

        Return _rt

    End Function

    ''' <summary>
    ''' Funktion zum öffnen einer SFDL Datei
    ''' </summary>
    Public Sub OpenSFDLFile(ByVal _file As String)

        Dim _sfdl_file As New SFDL_File
        Const SFDLFILEVERSION As Integer = 4
        Dim _controls() As Control
        Dim _list_controls As New List(Of Control)

        Try

            frm_main.MainLayoutPanel.Controls.Clear()
            frm_main.chk_Panel_Header.Checked = True
            frm_main.AlleMakierenToolStripMenuItem.Checked = True
            frm_main.SetFullDownloadSize = 0

            _sfdl_file = CType(XMLDeSerialize(_sfdl_file, _file), SFDL_File)

            'Versions Check

            If _sfdl_file.GetSetFileVersion > SFDLFILEVERSION Then
                Throw New Exception("Die SFDL Loader ist nicht kompatibel zu dieser SFDL Datei. Bitte lade dir die aktuellste Version herunter!")
            End If

            If _sfdl_file.GetSetEncryptet = True Then

                Dim _password As String = String.Empty
                Dim _crypto As New Crypto.AES

                'Decrypt

                frm_opensfdl_encrypted.SetTestDecryptString = _sfdl_file.GetsetUploader

                If frm_opensfdl_encrypted.ShowDialog() = DialogResult.OK Then

                    _password = frm_opensfdl_encrypted.GetPassword

                    frm_opensfdl_encrypted.Dispose()

                    _sfdl_file.GetSetDescription = _crypto.DecryptString(_sfdl_file.GetSetDescription, _password)
                    _sfdl_file.GetsetUploader = _crypto.DecryptString(_sfdl_file.GetsetUploader, _password)

                    For Each _file_info In _sfdl_file.GetSetFileInfoList

                        _file_info.GetSetDirectoryPath = _crypto.DecryptString(_file_info.GetSetDirectoryPath, _password)
                        _file_info.GetSetDirectoryRoot = _crypto.DecryptString(_file_info.GetSetDirectoryRoot, _password)
                        _file_info.GetSetFileFullPath = _crypto.DecryptString(_file_info.GetSetFileFullPath, _password)
                        _file_info.GetSetFileName = _crypto.DecryptString(_file_info.GetSetFileName, _password)
                        _file_info.GetSetMD5FileHash = _crypto.DecryptString(_file_info.GetSetMD5FileHash, _password)

                    Next

                    _sfdl_file.GetSetConnectionInfo.GetSetHost = _crypto.DecryptString(_sfdl_file.GetSetConnectionInfo.GetSetHost, _password)
                    _sfdl_file.GetSetConnectionInfo.GetSetName = _crypto.DecryptString(_sfdl_file.GetSetConnectionInfo.GetSetName, _password)
                    _sfdl_file.GetSetConnectionInfo.GetSetPassword = _crypto.DecryptString(_sfdl_file.GetSetConnectionInfo.GetSetPassword, _password)
                    _sfdl_file.GetSetConnectionInfo.GetSetPath = _crypto.DecryptString(_sfdl_file.GetSetConnectionInfo.GetSetPath, _password)
                    _sfdl_file.GetSetConnectionInfo.GetSetUsername = _crypto.DecryptString(_sfdl_file.GetSetConnectionInfo.GetSetUsername, _password)

                Else
                    frm_opensfdl_encrypted.Dispose()
                    Exit Sub
                End If

            End If

            frm_main.GetSetCurrentSFDLFile = _sfdl_file
            frm_main.GetSetCurrentSFDLFilePath = _file

            If Not String.IsNullOrEmpty(_sfdl_file.GetsetUploader) Then
                frm_main.ToolInfo.DropDownItems.Add("Uploader: " & _sfdl_file.GetsetUploader, My.Resources.upper)
                frm_main.ToolInfo.Visible = True
            End If

            If Not String.IsNullOrEmpty(_sfdl_file.GetSetDescription) Then
                frm_main.ToolInfo.DropDownItems.Add("Beschreibung: " & _sfdl_file.GetSetDescription, My.Resources.desciption)
                frm_main.ToolInfo.Visible = True
            End If

            If frm_main.bgw_whois.IsBusy = False Then
                frm_main.bgw_whois.RunWorkerAsync(_sfdl_file.GetSetConnectionInfo.GetSetHost)
            End If

            '  frm_main.bgw_open_sfdl_file.RunWorkerAsync()

            For Each _dl_file In _sfdl_file.GetSetFileInfoList


                Dim _ctrftp As New ctrFTPClient
                Dim _local_file As String = String.Empty


                _ctrftp.lbl_file_name.Text = _dl_file.GetSetFileName
                _ctrftp.lbl_file_size.Text = CStr(_dl_file.GetSetFileSize)
                _ctrftp.lbl_dl_speed_status.Text = "0 KB/s"
                _ctrftp.ProgBarStatus.Value = 0

                _ctrftp.FileInfo = _dl_file
                _ctrftp.ConnectionInfo = _sfdl_file.GetSetConnectionInfo
                _ctrftp.GetSetSFDLFilename = IO.Path.GetFileNameWithoutExtension(_file)
                _ctrftp.GetSetSFDLDesciption = _sfdl_file.GetSetDescription
                _ctrftp.GetSetSFDLContainerVersion = _sfdl_file.GetSetFileVersion

                Try

                    _local_file = GetDownloadFilePath(frm_main.GetSettings, _sfdl_file.GetSetDescription, IO.Path.GetFileNameWithoutExtension(_file), _dl_file)

                    If IO.File.Exists(_local_file) Then

                        Dim _tmp_file_info As New IO.FileInfo(_local_file)

                        'Wenn Datei existiert und die richtige größe hat brauchen wir es nicht nochmal herunterladen
                        If _tmp_file_info.Length = _dl_file.GetSetFileSize Then
                            _ctrftp.chkActivate.Checked = False
                        End If


                    End If

                Catch ex As Exception
                    'Fehler aufangen
                End Try

                _list_controls.Add(_ctrftp)

            Next

            frm_main.MainLayoutPanel.Controls.AddRange(_list_controls.ToArray)

            MemoryManagement.FlushMemory()

        Catch ex As Exception

            MessageBox.Show("SFDL Datei konnte nicht geöffnet werden!" & vbNewLine & ex.Message, "Fehler", MessageBoxButtons.OK, MessageBoxIcon.Error)

            frm_main.MainLayoutPanel.Controls.Clear()
            frm_main.chk_Panel_Header.Checked = True
            frm_main.AlleMakierenToolStripMenuItem.Checked = True
            frm_main.SetFullDownloadSize = 0
            frm_main.ToolInfo.Visible = False

        End Try

    End Sub


    Public Function GetDownloadFilePath(ByVal _settings As Settings, ByVal _sfdl_description As String, ByVal _sfdl_filename As String, ByVal _file_info As FileInfo) As String

        Dim _download_dir As String = String.Empty
        Dim _tmp_last_sub_dir As String = String.Empty
        Dim _dowload_local_filename As String

        If _settings.GetSetCreateDownloadDir Then

            If _settings.GetSetCreateDownloadDirUseDescription = True And String.IsNullOrEmpty(_sfdl_description) = False Then
                _download_dir = IO.Path.Combine(_settings.GetSetDownloadDirectory, _sfdl_description)
            Else
                _download_dir = IO.Path.Combine(_settings.GetSetDownloadDirectory, _sfdl_filename)
            End If

        Else
            _download_dir = _settings.GetSetDownloadDirectory
        End If


        If Not String.IsNullOrEmpty(_file_info.GetSetDirectoryRoot) Then

            _tmp_last_sub_dir = _file_info.GetSetDirectoryPath.Replace(_file_info.GetSetDirectoryRoot, "")

            If Not String.IsNullOrEmpty(_tmp_last_sub_dir) Then
                _tmp_last_sub_dir = _tmp_last_sub_dir.Replace("/", "\")

                If _tmp_last_sub_dir.StartsWith("\") Then
                    _tmp_last_sub_dir = _tmp_last_sub_dir.Remove(0, 1)
                End If

                _download_dir = IO.Path.Combine(_download_dir, _tmp_last_sub_dir)

            End If

        End If

        If Not IO.Directory.Exists(_download_dir) Then
            IO.Directory.CreateDirectory(_download_dir)
        End If

        _dowload_local_filename = IO.Path.Combine(_download_dir, _file_info.GetSetFileName)

        Return _dowload_local_filename


    End Function

    ''' <summary>
    ''' Konvertiert eine Dezimale Zeitangabe in eine lesbare Angabe.
    ''' </summary>
    Public Function ConvertDecimal2Time(ByVal value As Double) As String
        Try
            Dim valueTime As TimeSpan = TimeSpan.FromMinutes(value)
            If valueTime.Hours.Equals(0) Then
                Return String.Format("{0:D2}:{1:D2}", valueTime.Minutes, valueTime.Seconds)
            End If
            Return String.Format("{0:D2}:{1:D2}:{2:D2}", valueTime.Hours, valueTime.Minutes, valueTime.Seconds)
        Catch
            Return "0"
        End Try
    End Function

    ''' <summary>
    ''' Function to download Image from website
    ''' </summary>
    ''' <param name="_URL">URL address to download image</param>
    ''' <return>Image</return>
    Public Function DownloadImage(ByVal _URL As String) As Image
        Dim _tmpImage As Image = Nothing

        Try
            ' Open a connection
            Dim _HttpWebRequest As System.Net.HttpWebRequest = CType(System.Net.HttpWebRequest.Create(_URL), System.Net.HttpWebRequest)

            _HttpWebRequest.AllowWriteStreamBuffering = True

            ' You can also specify additional header values like the user agent or the referer: (Optional)
            _HttpWebRequest.UserAgent = "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1)"
            _HttpWebRequest.Referer = "http://www.google.com/"

            ' set timeout for 20 seconds (Optional)
            _HttpWebRequest.Timeout = 20000

            ' Request response:
            Dim _WebResponse As System.Net.WebResponse = _HttpWebRequest.GetResponse()

            ' Open data stream:
            Dim _WebStream As System.IO.Stream = _WebResponse.GetResponseStream()

            ' convert webstream to image
            _tmpImage = Image.FromStream(_WebStream)

            ' Cleanup
            _WebResponse.Close()
            _WebResponse.Close()
        Catch _Exception As Exception
            ' Error
            Console.WriteLine("Exception caught in process: {0}", _Exception.ToString())
            Return Nothing
        End Try

        Return _tmpImage

    End Function

    Public Enum EXECUTION_STATE
        ' Stay in working state by resetting display idle timer
        ES_SYSTEM_REQUIRED = &H1
        ' Force display on by resetting system idle timer
        ES_DISPLAY_REQUIRED = &H2
        ' Force this state until next ES_CONTINUOUS call
        ' and one of the other flags are cleared
        ES_CONTINUOUS = &H80000000
    End Enum

    ''' <summary>
    ''' Verhindert das der Computer in den Stand-by Modus geht
    ''' </summary>
    ''' <return></return>
    ''' <remarks></remarks>
    Public Function No_Sleep() As EXECUTION_STATE

        Try

            Return SetThreadExecutionState(EXECUTION_STATE.ES_SYSTEM_REQUIRED Or _
                   EXECUTION_STATE.ES_CONTINUOUS Or EXECUTION_STATE.ES_DISPLAY_REQUIRED)

        Catch ex As Exception
        End Try

    End Function

    ''' <summary>
    ''' Konvertiert Bytes in GB
    ''' </summary>
    Public Function ConvertBytesToGB(ByVal _bytes_value As Long) As String

        Dim _rt As String = String.Empty
        Dim _tmp As Double = 0

        If Not _bytes_value = 0 Then

            _tmp = CDbl(((_bytes_value / 1024) / 1024) / 1024)

            _tmp = Math.Round(_tmp, 3)

            _rt = _tmp & " GB"

        Else
            _rt = "0 GB"
        End If


        Return _rt

    End Function

    Public Function RegisterSFDLURIHandler(ByVal _path As String) As Boolean


        Dim _reg_key As RegistryKey
        Dim _key_found As Boolean = False

        Try

            For Each _key In My.Computer.Registry.ClassesRoot.GetSubKeyNames
                If _key.ToString.Equals("sfdl") Then
                    _key_found = True
                End If
            Next

            If _key_found = True Then
                My.Computer.Registry.ClassesRoot.DeleteSubKeyTree("sfdl")
            End If

            _reg_key = My.Computer.Registry.ClassesRoot.CreateSubKey("sfdl")

            _reg_key.SetValue("", "URL:SFDL.NET Protocol Handler")

            _reg_key.SetValue("URL Protocol", "", RegistryValueKind.String)

            _reg_key = My.Computer.Registry.ClassesRoot.CreateSubKey("sfdl\DefaultIcon")

            _reg_key.SetValue("", Chr(34) & _path & Chr(34))

            My.Computer.Registry.ClassesRoot.CreateSubKey("sfdl\shell")
            My.Computer.Registry.ClassesRoot.CreateSubKey("sfdl\shell\open")

            _reg_key = My.Computer.Registry.ClassesRoot.CreateSubKey("sfdl\shell\open\command")

            _reg_key.SetValue("", Chr(34) & _path & Chr(34) & " " & Chr(34) & "%1" & Chr(34), RegistryValueKind.String)

        Catch ex As Exception
            Return False
        End Try

        Return True

    End Function

    Public Function DownloadFile(ByVal _url As String) As String

        Try

            ' Open a connection
            Dim _HttpWebRequest As System.Net.HttpWebRequest = CType(System.Net.HttpWebRequest.Create(_url), System.Net.HttpWebRequest)

            _HttpWebRequest.AllowWriteStreamBuffering = True

            ' You can also specify additional header values like the user agent or the referer: (Optional)
            _HttpWebRequest.UserAgent = "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1)"

            ' set timeout for 20 seconds (Optional)
            _HttpWebRequest.Timeout = 20000

            ' Request response:
            Dim _WebResponse As System.Net.WebResponse = _HttpWebRequest.GetResponse()

            ' Open data stream:
            Dim _WebStream As System.IO.Stream = _WebResponse.GetResponseStream()

            Dim _temp_file_path As String = IO.Path.Combine(My.Computer.FileSystem.SpecialDirectories.Temp, IO.Path.GetRandomFileName)

            Dim _filestream As FileStream = IO.File.OpenWrite(_temp_file_path)

            CopyStream(_WebStream, _filestream)

            ' Cleanup
            _WebResponse.Close()
            _WebResponse.Close()

            _filestream.Dispose()

            Return _temp_file_path

        Catch _Exception As Exception
            ' Error
            MessageBox.Show("SFDL File konnte nicht heruntergeladen werden!" & vbNewLine & "Orginal URL: " & _url, "ClicknLoad", MessageBoxButtons.OK, MessageBoxIcon.Error)
            Return String.Empty
        End Try


    End Function

    Private Shared Sub CopyStream(readStream As Stream, writeStream As Stream)

        Dim Length As Integer = 256
        Dim buffer As [Byte]() = New [Byte](Length - 1) {}
        Dim bytesRead As Integer = readStream.Read(buffer, 0, Length)
        ' write the required bytes
        While bytesRead > 0
            writeStream.Write(buffer, 0, bytesRead)
            bytesRead = readStream.Read(buffer, 0, Length)
        End While
        readStream.Close()
        writeStream.Close()

    End Sub

    Public Function ConvertEncodingEnumToEncoding(ByVal _encoding As Enums.CharacterEncoding) As System.Text.Encoding

        Select Case _encoding

            Case Enums.CharacterEncoding.Standard

                Return System.Text.Encoding.Default

            Case Enums.CharacterEncoding.UTF8

                Return System.Text.Encoding.UTF8

            Case Enums.CharacterEncoding.UTF7

                Return System.Text.Encoding.UTF7

            Case Enums.CharacterEncoding.ASCII

                Return System.Text.Encoding.ASCII

            Case Else

                Return System.Text.Encoding.Default

        End Select

    End Function

    Public Sub AddSeparator()

        Dim _lbl_control As New Label

        _lbl_control.Dock = DockStyle.Fill

        For x = 0 To frm_main.MainLayoutPanel.Size.Width
            _lbl_control.Text = _lbl_control.Text & "-"
        Next

        _lbl_control.ForeColor = Color.Green

        frm_main.MainLayoutPanel.Controls.Add(_lbl_control)

    End Sub

End Class
